/*
 * UartContext.cpp
 *
 *  Created on: Sep 5, 2017
 */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <memory.h>
#include <termio.h>
#include <sys/ioctl.h>
#include <base/time.hpp>
#include "uart/UartContext.h"
#include "utils/Log.h"
#include "ProtocolCustom.h"

#ifndef DEBUG
#define DEBUG LOGD("--%d-- --%s-- Debug!!!\n", __LINE__, __FILE__);
#endif

#define UART_DATA_BUF_LEN			16384	// 16KB
#define ACK_PERIOD				100	// 100ms

static Mutex sSendMutex;

extern int parseProtocolProduct(const BYTE *pData, UINT len);
extern int parseProtocolCustom(const uint8_t *pData, uint32_t len);

static const char* getBaudRate(UINT baudRate) {
	struct {
		UINT baud;
		const char *pBaudStr;
	} baudInfoTab[] = {
		{ B1200, "B1200" },
		{ B2400, "B2400" },
		{ B4800, "B4800" },
		{ B9600, "B9600" },
		{ B19200, "B19200" },
		{ B38400, "B38400" },
		{ B57600, "B57600" },
		{ B115200, "B115200" },
		{ B230400, "B230400" },
		{ B460800, "B460800" },
		{ B921600, "B921600" }
	};

	int len = sizeof(baudInfoTab) / sizeof(baudInfoTab[0]);
	for (int i = 0; i < len; ++i) {
		if (baudInfoTab[i].baud == baudRate) {
			return baudInfoTab[i].pBaudStr;
		}
	}

	return NULL;
}

static UartContext* uart1 = NULL;
static UartContext* uart2 = NULL;

void UartContext::init() {
	if(uart1 == NULL){
		uart1 = new UartContext(UART_TTYS1);
		uart1->openUart("/dev/ttyS1", B9600);
	}
	 if(uart2 == NULL){
	 	uart2 = new UartContext(UART_TTYS2);
	 	uart2->openUart("/dev/ttyS2", B9600);
	 }
}

void UartContext::destroy() {
    if (uart1) {
        delete uart1;
        uart1 = NULL;
    }
     if (uart2) {
         delete uart2;
         uart2 = NULL;
     }
}

bool UartContext::sendTo(int uart, const BYTE *pData, UINT len)
{
	if (uart == UART_TTYS1) {
		#ifdef TCP_TEST
			#if TCP_MODE == 1
			Tcp::clientSend(pData, len);
			#endif
		#endif
		
		Mutex::Autolock _l(sSendMutex);
		bool ret = uart1->send(pData, len);
		return ret;
	}
	else if (uart == UART_TTYS2) {
		return uart2->send(pData, len);
	}
	LOGD("no such uart\n");
	return false;
}


UartContext::UartContext(int uartNum) :
	mIsOpen(false),
	mUartID(0),
	mLastTime(0),
	mDataBufPtr(NULL),
	mDataBufLen(0),
	mUartNumber(uartNum){
}

UartContext::~UartContext() {
	delete[] mDataBufPtr;
	closeUart();
}

bool UartContext::openUart(const char *pFileName, UINT baudRate) {
	LOGD("openUart pFileName = %s, baudRate = %s\n", pFileName, getBaudRate(baudRate));
	mUartID = open(pFileName, O_RDWR|O_NOCTTY);

	if (mUartID <= 0) {
		mIsOpen = false;
	} else {
		struct termios oldtio = { 0 };
		struct termios newtio = { 0 };
		tcgetattr(mUartID, &oldtio);

		newtio.c_cflag = baudRate|CS8|CLOCAL|CREAD;
		newtio.c_iflag = 0;	// IGNPAR | ICRNL
		newtio.c_oflag = 0;
		newtio.c_lflag = 0;	// ICANON
		newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
		newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */
		tcflush(mUartID, TCIOFLUSH);
		tcsetattr(mUartID, TCSANOW, &newtio);

		// 设置为非阻塞 Set to non-blocking
		fcntl(mUartID, F_SETFL, O_NONBLOCK);

		mIsOpen = run("uart");
		if (!mIsOpen) {
			close(mUartID);
			mUartID = 0;
		}

		LOGD("openUart mIsOpen = %d\n", mIsOpen);
	}

	return mIsOpen;
}

void UartContext::closeUart() {
	LOGD("closeUart mIsOpen: %d...\n", mIsOpen);
	if (mIsOpen) {
		requestExit();

		close(mUartID);
		mUartID = 0;
		mIsOpen = false;
	}
}

bool UartContext::send(const BYTE *pData, UINT len) {
	if (!mIsOpen) {
		return false;
	}

#ifdef DEBUG_PRO_SEND
	std::string str;
	char tmp[4] = {4};
	for(uint32_t level1 = 0; level1 < len; ++level1)
	{
		snprintf(tmp, sizeof(tmp), "%.2X ", pData[level1]);
		str.append(tmp);
	}
	LOGD("--%d-- --%s-- size:%u 发送数据：%s\n", __LINE__, __FILE__, len, str.c_str());
#endif

	if (write(mUartID, pData, len) != (int) len) {	// fail
		LOGD("send Fail\n");
		return false;
	}

	// success
//	LOGD("send Success\n");

	return true;
}


bool UartContext::readyToRun() {
	if (mDataBufPtr == NULL) {
		mDataBufPtr = new BYTE[UART_DATA_BUF_LEN];
	}

	if (mDataBufPtr == NULL) {
		closeUart();
	}
	mLastTime = base::uptime();
	return (mDataBufPtr != NULL);
}

//延时
class DelayThread: public Thread {

public:
	virtual bool readyToRun() {
		 return true;
	}

	virtual bool threadLoop() {
		//检查是否有退出线程的请求，如果有，则返回false，立即退出线程
		if (exitPending()) {
			return false;
		}
		sleep(150);
		return false;
	}
};

static DelayThread delay_thread;

bool UartContext::threadLoop() {
	if (mIsOpen) {
		//冷热板协议
		if(UART_TTYS1 == mUartNumber){
			// 可能上一次解析后有残留数据，需要拼接起来
			int readNum = read(mUartID, mDataBufPtr + mDataBufLen, UART_DATA_BUF_LEN - mDataBufLen);

			if (readNum > 0) {
				mDataBufLen += readNum;
				// 解析协议
				int len = parseProtocolCustom(mDataBufPtr, mDataBufLen);

				if ((len > 0) && (len < mDataBufLen)) {
					// 将未解析的数据移到头部
					memcpy(mDataBufPtr, mDataBufPtr + len, mDataBufLen - len);
				}

				mDataBufLen -= len;
			} else {
				Thread::sleep(50);
			}

	//		  int64_t curTime = base::uptime();
			  if (!delay_thread.isRunning()) {
				protocol::ack();
	//		  	mLastTime = base::uptime();
				delay_thread.run();
			  }
		}

		// 制冰板协议
		if(UART_TTYS2 == mUartNumber){
			// 可能上一次解析后有残留数据，需要拼接起来
			int readNum = read(mUartID, mDataBufPtr + mDataBufLen, UART_DATA_BUF_LEN - mDataBufLen);

			if (readNum > 0) {
				mDataBufLen += readNum;

				// 解析协议
				int len = parseProtocolProduct(mDataBufPtr, mDataBufLen);
				if ((len > 0) && (len < mDataBufLen)) {
					// 将未解析的数据移到头部
					memcpy(mDataBufPtr, mDataBufPtr + len, mDataBufLen - len);
				}

				mDataBufLen -= len;
			} else {
				Thread::sleep(100);
				protocol::ackProduct();
			}
		}

		return true;
	}

	return false;
}
